import sys
from xml.sax import make_parser 
from xml.sax.handler import ContentHandler
#
from jd_handler import JD_Tag,JD_Handler
from jd_schema import SchemaTable,SchemaColumn

class Column(object):
    def __init__(self):
        self.isPrimary = False
        self.name = ''
        self.typeId = -1
        self.comment = ''

class Table(object):
    def __init__(self):
        self.name = ''
        self.columns = []

class DataType(object):
    def __init__(self):
        self.id = ''
        self.name = ''

class TypeDefine(object):
    def __init__(self,codeType,codeTypePrefix):
        self.codeType = codeType
        self.codeTypePrefix = codeTypePrefix

DATA_TYPE_MAP = {
'BIT':TypeDefine('bool','b'),
'BOOL':TypeDefine('bool','b'),
'TINYINT':TypeDefine('int','i'),
'SMALLINT':TypeDefine('int','i'),
'MEDIUMINT':TypeDefine('int','i'),
'INT':TypeDefine('int','i'),
'INTEGER':TypeDefine('int','i'),
'TIMESTAMP':TypeDefine('std::string','s'),
'BIGINT':TypeDefine('long long','l'),
'FLOAT':TypeDefine('float','f'),
'DOUBLE':TypeDefine('double','d'),
'DOUBLE PRECISION':TypeDefine('double','d'),
'REAL':TypeDefine('double','d'),
'CHAR':TypeDefine('std::string','s'),
'VARCHAR':TypeDefine('std::string','s'),
'TINYBLOB':TypeDefine('std::string','s'),
'BLOB':TypeDefine('std::string','s'),
'MEDIUMBLOB':TypeDefine('std::string','s'),
'LONGBLOB':TypeDefine('std::string','s'),
'TINYTEXT':TypeDefine('std::string','s'),
'TEXT':TypeDefine('std::string','s'),
'MEDIUMTEXT':TypeDefine('std::string','s'),
'LONGTEXT':TypeDefine('std::string','s'),
'TEXT':TypeDefine('std::string','s'),
'-_-':TypeDefine('UNKNOWN','-_-')
}   

class DBDesignerHandler(JD_Handler):
    def __init__(self):
        #essential info
        basicSchema = {'DATATYPE':JD_Tag(4), 'TABLE':JD_Tag(4), 'COLUMN':JD_Tag(6) }
        JD_Handler.__init__(self, basic=basicSchema)
        #data-type
        self.DataType = None
        self.DataTypes = {}
        #table
        self.Tb = None
        self.Tbs = []
        #column
        self.Col = None
    
    def characters(self, content):
        if self.expect_tag('COLUMN') or self.expect_tag('TABLE') or self.expect_tag('DATATYPE'):
            self.chars.append(content)
    
    def startElement(self, name, atts):
        self.in_tag(name)
        
        try:
            if self.expect_tag('COLUMN'):
                self.Col = Column()
                self.Col.name = atts['ColName']
                self.Col.typeId = atts['idDatatype']
                self.Col.isPrimary = int(atts['PrimaryKey'])
                self.Col.comment = atts['Comments']
            elif self.expect_tag('TABLE'):
                self.Tb = Table()
                self.Tb.name = atts['Tablename']
            elif self.expect_tag('DATATYPE'):
                self.DataType = DataType()
                self.DataType.id = atts['ID']
                self.DataType.name = atts['TypeName']
        except:
            print "Err:%s, with %d attrs" % ( name, len(atts) )
            for k, v in atts.items():
                print '%s="%s"' % (k,v)
    
    def endElement(self, name):
        if self.expect_tag('COLUMN') and self.Tb and self.Col :
            self.Tb.columns.append(self.Col)
        if self.expect_tag('TABLE') and self.Tb :
            self.Tbs.append(self.Tb)
        if self.expect_tag('DATATYPE') and self.DataType :
            self.DataTypes[self.DataType.id] = self.DataType
        
        self.out_tag(name)

    def getSchemaTables(self):
        schemaTables = []
        for table in self.Tbs:
            schmTable = SchemaTable(table.name)
            for column in table.columns:
                sTYPE = '-_-'
                if self.DataTypes.has_key(column.typeId):
                    sTYPE = self.DataTypes[column.typeId]
                try:
                    typeDef = DATA_TYPE_MAP[sTYPE.name]
                except:
                    typeDef = DATA_TYPE_MAP['-_-']
                #fix timestamp-type to string-type
                if 'int'==typeDef.codeType and column.name.lower().find('time')>=0:
                    typeDef = DATA_TYPE_MAP['TIMESTAMP']
                schmColumn = SchemaColumn(column.name, typeDef.codeType, typeDef.codeTypePrefix)
                if column.isPrimary :
                    schmColumn.isPK = True
                    schmTable.pks.append(schmColumn)
                schmTable.columns.append(schmColumn)
            schemaTables.append(schmTable)
        return schemaTables

